package de.fhwf.mixedreality.agent;

import javax.swing.JFrame;
import javax.swing.JOptionPane;

import de.fhwf.mixedreality.client.AgentView;
import de.fhwf.mixedreality.client.AgentViewEx;
import de.fhwf.mixedreality.client.IClient;
import de.fhwf.mixedreality.client.IView;
import de.fhwf.mixedreality.client2007.Client2007;
import de.fhwf.mixedreality.client2008.Client2008;

public abstract class AbstractBot implements Runnable {
	public enum ServerType { Server2007, Server2008 };
	
	private IClient mClient;
	private AgentView mView;
	private boolean mRunning = false;
	private Thread mThread;
	private boolean mSimulationMode;

	public AbstractBot(String server, ServerType type, IClient.Team team, int vtID, int rcID, String botName, boolean simulationMode) {
		this(server, type, team, vtID, rcID, botName, "", simulationMode, null);
	}

	public AbstractBot(String server, ServerType type, IClient.Team team, int vtID, int rcID, String botName, String teamName, boolean simulationMode) {
		this(server, type, team, vtID, rcID, botName, teamName, simulationMode, null);
	}

	public AbstractBot(String server, ServerType type, IClient.Team team, int vtID, int rcID, String botName, boolean simulationMode, IView useView) {
		this(server, type, team, vtID, rcID, botName, "", simulationMode, useView);
	}
	
	public AbstractBot(String server, ServerType type, IClient.Team team, int vtID, int rcID, String botName, String teamName, boolean simulationMode, IView useView) {
		if (type == ServerType.Server2007) {
		 mClient = new Client2007(server, team);
		} else {
		 mClient = new Client2008(server, team, vtID, rcID);
		}
		mSimulationMode = simulationMode;
		
		if (useView != null){
			System.out.println("[AbstractBot] AbstractBot: Using external view");
			mView = (AgentView) useView;
			mClient.setView(useView);
		} else {
			JFrame mFrame = new JFrame();
			mFrame.setSize(800, 600);
			mFrame.setLayout(null);
			mFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
			mFrame.setVisible(true);
			
			if (mSimulationMode) {
				mView = new AgentViewEx(800, 600);
				mFrame.setTitle("Agent view (simulation mode)");
				mFrame.getContentPane().addMouseListener((AgentViewEx) mView);
				mFrame.getContentPane().addMouseMotionListener((AgentViewEx) mView);
				mFrame.addWindowListener((AgentViewEx) mView);
				mFrame.add(mView);
			} else {
				mView = new AgentView(800, 600);
				mFrame.setTitle("Agent view");
				mFrame.add(mView);
			}
			mClient.setView(mView);
		}
		if (!botName.equals("")) {
			mClient.setBotName(botName);
		}
		if (!teamName.equals("")) {
			mClient.setTeamName(teamName);
		} else {
			mClient.setTeamName(team.toString());
		}
		mThread = new Thread(this);
	}

	public boolean start() {
		if (!mSimulationMode) {
			if (!mClient.connect()) {
				System.err.println("[AbstractBot] start: Could not connect to server!");
				return false;
			}
		}
		mRunning = true;
		mThread.start();
		System.out.println("[AbstractBot] start: Bot started!");
		return true;
	}

	public boolean isRunning() {
		return mRunning;
	}

	public void stop() {
		mRunning = false;
		System.out.println("[AbstractBot] stop: Bot stopped!");
	}

	public void run() {
		boolean waitingToStart = true;
		
		startup(mClient);
		
		while (mRunning) {
			if (mSimulationMode) {
				if (!mClient.update(((AgentViewEx)mView).getVirtualWorld(mClient))) {
					break;
				}
			} else {
				if (!mClient.update()) {
					if (!waitingToStart) {
  					if (askToDisconnect()) {
  						break;
  					} else {
  						mClient.connect();
  					}
					}
				} else {
					waitingToStart = false;
				}
			}
			
			if (!process(mClient, mView)) {
				break;
			}
			
			mClient.flush();			
		}

		terminate(mClient);
		
		mClient.close();
		mRunning = false;
	}

	public abstract void startup(IClient client);
	public abstract boolean process(IClient client, AgentView view);
	public abstract void terminate(IClient client);
	
	public IView getAgentView() {
		return mView;
	}

	public IClient getClient() {
		return mClient;
	}
		
	private boolean askToDisconnect() {
		int ret = JOptionPane.showConfirmDialog(null, "The connection to the server was lost.\nClose Client?", "Connection failure", JOptionPane.YES_NO_OPTION);
		return (ret == JOptionPane.YES_OPTION);
	}
}
